package com.doctcloud.common.mongo.service.impl;
import com.doctcloud.common.mongo.service.BaseMongoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Optional;
/**
 * MongoDB 通用基础服务类，封装常用 CRUD 操作
 *
 * @param <T>  实体类类型
 * @param <ID> 主键类型（通常为 String）
 */
public abstract class BaseMongoServiceImpl<T, ID extends Serializable> implements BaseMongoService<T, ID> {

    @Autowired
    protected MongoTemplate mongoTemplate;

    /**
     * 实体类的 Class 对象（通过泛型反射获取）
     */
    protected Class<T> entityClass;

    @SuppressWarnings("unchecked")
    public BaseMongoServiceImpl() {
        // 通过反射获取泛型 T 的实际类型
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.entityClass = (Class<T>) type.getActualTypeArguments()[0];
    }

    /**
     * 保存或更新实体（存在则更新，不存在则新增）
     *
     * @param entity 实体对象
     * @return 保存后的实体
     */
    @Override
    public T saveOrUpdate(T entity) {
        Assert.notNull(entity, "实体对象不能为 null");
        return mongoTemplate.save(entity);
    }

    /**
     * 根据 ID 查询实体
     *
     * @param id 主键 ID
     * @return 实体对象（Optional 包装，避免 NPE）
     */
    @Override
    public Optional<T> findById(ID id) {
        Assert.notNull(id, "ID 不能为 null");
        T entity = mongoTemplate.findById(id, entityClass);
        return Optional.ofNullable(entity);
    }

    /**
     * 查询所有实体
     *
     * @return 实体列表
     */
    @Override
    public List<T> findAll() {
        return mongoTemplate.findAll(entityClass);
    }

    /**
     * 根据条件查询实体列表
     *
     * @param query 查询条件（MongoDB Query 对象）
     * @return 符合条件的实体列表
     */
    @Override
    public List<T> findByQuery(Query query) {
        Assert.notNull(query, "查询条件不能为 null");
        return mongoTemplate.find(query, entityClass);
    }

    /**
     * 分页查询所有实体
     *
     * @param pageable 分页参数（页码、每页条数、排序等）
     * @return 分页结果
     */
    @Override
    public Page<T> findAll(Pageable pageable) {
        Assert.notNull(pageable, "分页参数不能为 null");
        Query query = new Query().with(pageable);
        long total = mongoTemplate.count(query, entityClass);
        List<T> content = mongoTemplate.find(query, entityClass);
        return new org.springframework.data.domain.PageImpl<>(content, pageable, total);
    }

    /**
     * 根据条件分页查询
     *
     * @param query    查询条件
     * @param pageable 分页参数
     * @return 分页结果
     */
    @Override
    public Page<T> findByQuery(Query query, Pageable pageable) {
        Assert.notNull(query, "查询条件不能为 null");
        Assert.notNull(pageable, "分页参数不能为 null");
        query.with(pageable); // 绑定分页参数
        long total = mongoTemplate.count(query, entityClass);
        List<T> content = mongoTemplate.find(query, entityClass);
        return new org.springframework.data.domain.PageImpl<>(content, pageable, total);
    }

    /**
     * 根据 ID 删除实体
     *
     * @param id 主键 ID
     */
    @Override
    public boolean deleteById(ID id) {
        // 1. 先查询 ID 是否存在
        boolean exists = existsById(id);
        if (!exists) {
            return false; // ID 不存在，未删除任何数据
        }

        // 2. 执行删除（根据 ID 构建查询条件）
        Query query = Query.query(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, entityClass);

        return true; // 成功删除已存在的 ID
    }

    /**
     * 根据条件删除实体
     *
     * @param query 删除条件
     */
    @Override
    public void deleteByQuery(Query query) {
        Assert.notNull(query, "删除条件不能为 null");
        mongoTemplate.remove(query, entityClass);
    }

    /**
     * 根据条件更新实体（单条更新）
     *
     * @param query  更新条件
     * @param update 更新内容
     */
    @Override
    public void updateFirst(Query query, Update update) {
        Assert.notNull(query, "更新条件不能为 null");
        Assert.notNull(update, "更新内容不能为 null");
        mongoTemplate.updateFirst(query, update, entityClass);
    }

    /**
     * 根据条件更新所有符合条件的实体（批量更新）
     *
     * @param query  更新条件
     * @param update 更新内容
     */
    @Override
    public void updateMulti(Query query, Update update) {
        Assert.notNull(query, "更新条件不能为 null");
        Assert.notNull(update, "更新内容不能为 null");
        mongoTemplate.updateMulti(query, update, entityClass);
    }

    /**
     * 判断 ID 是否存在
     *
     * @param id 主键 ID
     * @return true：存在；false：不存在
     */
    @Override
    public boolean existsById(ID id) {
        Assert.notNull(id, "ID 不能为 null");
        return mongoTemplate.exists(new Query(Criteria.where("_id").is(id)), entityClass);
    }

    /**
     * 根据条件统计数量
     *
     * @param query 统计条件
     * @return 符合条件的记录数
     */
    @Override
    public long count(Query query) {
        Assert.notNull(query, "统计条件不能为 null");
        return mongoTemplate.count(query, entityClass);
    }
}